<script setup lang="ts">
import {
  DataTableBaseColumn,
  DataTableColumns,
  DataTableFilterState,
  DataTableInst,
  FormInst,
  FormItemRule,
  FormRules,
  NButton,
  NButtonGroup,
  NPopconfirm,
  NSpace,
  PaginationInfo,
  PaginationProps
} from "naive-ui";
import type {SysNotice} from "@/api/notice/types.ts";
import {noticeApi} from "@/api/notice";
import {dateFormatByNumber, dateParse, isEmpty, isNotNull, resetToNull} from "@/utils";
import {useDictStore} from "@/stores";
import {userApi} from "@/api/user";

enum ModeTypeEnum {
  ADD = '新增',
  MODIFY = '修改',
  DETAIL = '详情'
}

enum NoticeReceiveTypeEnum {
  ALL = 0,
  USER = 1
}

enum NoticeStatusEnum {
  EXPIRED = 0,
  NOT_PUBLISHED = 1,
  PUBLISHED = 2
}

interface PageQuery {
  noticeReceiveType: number | null;
  noticeTitle: string;
  noticeType: string;
  noticePublishedDateTimeRange: [string, string];
  noticeStatus: number | null;
}

const dictStore = useDictStore();
const pageQuery = reactive(<PageQuery>{})
const tableLoading = ref(false);
const tableRef = ref<DataTableInst | null>(null)
const tableColumns = ref<DataTableColumns<SysNotice>>([
  {title: '标题', key: 'noticeTitle', resizable: true, width: 120, ellipsis: {tooltip: true}},
  {title: '描述', key: 'noticeDesc', resizable: true, width: 120, ellipsis: {tooltip: true}},
  {
    title: '类型', key: 'noticeType',
    render: (row) => dictStore.renderTag('notice-type', row.noticeType),
    filter: true,
    filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('notice-type')
  },
  {
    title: '接受类型', key: 'noticeReceiveType',
    render: (row) => dictStore.renderTag('notice-receive-type', row.noticeReceiveType),
    filter: true,
    filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('notice-receive-type')
  },
  {title: '发布时间', key: 'noticePublishTime', resizable: true, ellipsis: {tooltip: true}},
  {
    title: '状态', key: 'noticeStatus',
    render: (row) => dictStore.renderTag('notice-status', row.noticeStatus),
    filter: true,
    filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('notice-status')
  },
  {title: '操作', key: 'action', align: 'center', render: row => tableActionRender(row)}
])
const tablePagination = reactive<PaginationProps>({
  prefix: (info: PaginationInfo) => {
    return `共 ${info.itemCount} 条记录`
  },
  showSizePicker: true,
  pageSizes: [10, 20, 50, 100],
  itemCount: 0,
  pageCount: 0,
  onChange: (page: number) => {
    tablePagination.page = page
    handlePageQuery()
  },
  onUpdatePageSize: (pageSize: number) => {
    tablePagination.pageSize = pageSize
    tablePagination.page = 1
    handlePageQuery()
  }
})
const tableData = ref<SysNotice[]>([])

const drawerDetailShow = ref(false)
const drawerDetailTitle = ref()
const drawerDetailFormRef = ref<FormInst | null>(null)
const drawerDetailSubmitLoading = ref(false)
const drawerNoticeReceiverSelectOption = ref<{ value: string, label: string }[]>([])
const drawerNoticeReceiverLoading = ref(false)
const drawerDetailFormModel = reactive<SysNotice & {
  noticePublishTimeNumber: number,
  noticeExpireTimeNumber: number
}>(<SysNotice & { noticePublishTimeNumber: number, noticeExpireTimeNumber: number }>{})
const drawerDetailFormRules = reactive<FormRules>({
  noticeTitle: {required: true, message: '请输入标题', trigger: 'blur'},
  noticeDesc: {required: true, message: '请输入描述', trigger: 'blur'},
  noticeContent: {required: true, message: '请输入内容', trigger: 'blur'},
  noticeType: {required: true, message: '请选择类型', trigger: 'blur'},
  noticeIcon: {
    trigger: 'blur', validator: (rule: FormItemRule, value: string) => {
      return new Promise<void>((resolve, reject) => {
        if (drawerDetailFormModel.noticeType === 'custom' && isEmpty(value)) {
          reject(new Error('请选择自定义图标'))
        } else {
          resolve()
        }
      })
    }
  },
  noticeReceiveType: {required: true, message: '请选择接收类型', trigger: 'blur', type: 'number'},
  noticeReceiverIds: {
    trigger: 'blur', validator: (rule: FormItemRule, value: string[]) => {
      return new Promise<void>((resolve, reject) => {
        if (drawerDetailFormModel.noticeReceiveType === NoticeReceiveTypeEnum.USER && isEmpty(value)) {
          reject(new Error('请选择接收用户'))
        } else {
          resolve()
        }
      })
    }
  },
  noticePublishTimeNumber: {required: true, message: '请选择发布时间', trigger: 'blur', type: 'number'},
})

onMounted(() => {
  dictStore.loadDict(['notice-receive-type', 'notice-status', 'notice-type'])
  handlePageQuery()
})

const tableActionRender = (row: SysNotice) => {
  let noticeActionBtn = [];
  if (row.noticeStatus === NoticeStatusEnum.PUBLISHED) {
    noticeActionBtn.push(h(NButton, {
      tertiary: true,
      type: 'warning',
      onClick: () => handleClickRevoke(row.id)
    }, {default: () => '撤销'}), h(NButton, {
      tertiary: true,
      type: 'default',
      onClick: () => handleClickDetail(row.id)
    }, {default: () => '详情'}))
  } else if (row.noticeStatus === NoticeStatusEnum.NOT_PUBLISHED) {
    noticeActionBtn.push(h(NButton, {
          tertiary: true,
          type: 'info',
          onClick: () => handleClickPublish(row.id)
        }, {default: () => '发布'}),
        h(NButton, {
          tertiary: true,
          type: 'primary',
          onClick: () => handleClickModify(row.id)
        }, {default: () => '修改'}))
  }
  noticeActionBtn.push(
      h(NPopconfirm, {onPositiveClick: () => handleClickDelete(row.id)}, {
        trigger: () => h(NButton, {
          tertiary: true,
          type: 'error',
        }, {default: () => '删除'}),
        default: () => `确定删除该(${row.noticeTitle})通知吗？`
      }))
  return h(NButtonGroup, {size: 'small'}, {
    default: () => noticeActionBtn
  })
}


const handlePageQuery = () => {
  tableLoading.value = true
  const {noticePublishedDateTimeRange, ...rest} = pageQuery
  noticeApi.page({
    ...rest,
    noticePublishTimeStart: noticePublishedDateTimeRange?.[0],
    noticePublishTimeEnd: noticePublishedDateTimeRange?.[1],
    current: tablePagination.page ?? 1,
    size: tablePagination.pageSize ?? 10
  }).then(res => {
    tableData.value = res.data.records
    tablePagination.itemCount = res.data.total
    tablePagination.pageCount = res.data.pages
  }).finally(() => tableLoading.value = false)
}
const initDrawerDetail = (type: ModeTypeEnum) => {
  drawerDetailShow.value = true
  drawerDetailTitle.value = type
}

const handleClickAdd = () => {
  initDrawerDetail(ModeTypeEnum.ADD)
  drawerDetailFormModel.noticeType = dictStore.getDictDefault('notice-type').dictValue as string
  drawerDetailFormModel.noticeReceiveType = dictStore.getDictDefault('notice-receive-type').dictValue as number
}
const handleClickReset = () => {
  resetToNull(pageQuery)
  tableRef.value?.filter(null)
  handlePageQuery()
}
const handleClickDetail = (id: string) => {
  noticeApi.detail(id).then(res => {
    Object.assign(drawerDetailFormModel, res.data)
    drawerDetailFormModel.noticePublishTimeNumber = dateParse(res.data.noticePublishTime).getTime()
    if (res.data.noticeExpireTime) {
      drawerDetailFormModel.noticeExpireTimeNumber = dateParse(res.data.noticeExpireTime).getTime()
    }
    initDrawerDetail(ModeTypeEnum.DETAIL)
  })
}

const handleClickModify = (id: string) => {
  noticeApi.detail(id).then(res => {
    Object.assign(drawerDetailFormModel, res.data)
    drawerDetailFormModel.noticePublishTimeNumber = dateParse(res.data.noticePublishTime).getTime()
    if (res.data.noticeExpireTime) {
      drawerDetailFormModel.noticeExpireTimeNumber = dateParse(res.data.noticeExpireTime).getTime()
    }
    initDrawerDetail(ModeTypeEnum.MODIFY)
  })
}

const handleClickDelete = (id: string) => {
  noticeApi.delete(id).then(res => {
    window.$message?.success(res.message)
    handlePageQuery()
  })
}

const handleClickPublish = (id: string) => {
  noticeApi.publish(id).then(res => {
    window.$message?.success(res.message)
    handlePageQuery()
  })
}

const handleClickRevoke = (id: string) => {
  noticeApi.revoke(id).then(res => {
    window.$message?.success(res.message)
    handlePageQuery()
  })
}

const handleBlurNoticeReceiverSelect = () => {
  if (drawerNoticeReceiverSelectOption.value.length === 0) {
    drawerNoticeReceiverLoading.value = true
    userApi.list({userStatus: 1}).then(res => {
      res.data.forEach(e => {
        drawerNoticeReceiverSelectOption.value.push({
          value: e.id,
          label: e.nickname
        })
      })
    }).finally(() => drawerNoticeReceiverLoading.value = false)
  }
}

const handleDrawerClose = () => {
  drawerDetailShow.value = false
  resetToNull(drawerDetailFormModel)
  drawerNoticeReceiverSelectOption.value = []
  handlePageQuery()
}


const handleClickSubmit = () => {
  drawerDetailFormRef.value?.validate(errors => {
    drawerDetailSubmitLoading.value = true
    if (!errors) {
      drawerDetailFormModel.noticePublishTime = dateFormatByNumber(drawerDetailFormModel.noticePublishTimeNumber)
      drawerDetailFormModel.noticeExpireTime = isNotNull(drawerDetailFormModel.noticeExpireTimeNumber) ? dateFormatByNumber(drawerDetailFormModel.noticeExpireTimeNumber) : null
      switch (drawerDetailTitle.value) {
        case ModeTypeEnum.ADD:
          noticeApi.add(drawerDetailFormModel).then(res => {
            window.$message?.success(res.message)
            drawerDetailShow.value = false
          });
          break;
        case ModeTypeEnum.MODIFY:
          noticeApi.modify(drawerDetailFormModel).then(res => {
            window.$message?.success(res.message)
            drawerDetailShow.value = false
          })
          break;
      }
    }
  }).finally(() => drawerDetailSubmitLoading.value = false)
}

</script>
<template>
  <n-card class="notice-manage">
    <template #header>
      <n-space vertical>
        <n-space>
          <n-input v-model:value="pageQuery.noticeTitle" placeholder="请输入通知标题"/>
          <n-date-picker
              v-model:formatted-value="pageQuery.noticePublishedDateTimeRange"
              value-format="yyyy-MM-dd HH:mm:ss"
              type="datetimerange"
              default-time="00:00:00"
              placeholder="请选择通知发布时间"
              clearable
          />
        </n-space>
        <n-space>
          <n-button
              secondary
              @click="handlePageQuery"
              :loading="tableLoading"
          >查询
          </n-button>
          <n-button
              secondary
              type="primary"
              @click="handleClickAdd"
          >新增
          </n-button>
          <n-button
              secondary
              type="warning"
              @click="handleClickReset"
          >重置
          </n-button>
        </n-space>
      </n-space>
    </template>
    <n-data-table
        remote
        ref="tableRef"
        :loading="tableLoading"
        :columns="tableColumns"
        :data="tableData"
        :pagination="tablePagination"
        @update:filters="(filters: DataTableFilterState, {key}: DataTableBaseColumn) => {
          pageQuery[key] = filters[key]
          handlePageQuery()
        }"
    />
  </n-card>
  <n-drawer
      v-model:show="drawerDetailShow"
      :width="600"
      placement="right"
      :on-after-leave="handleDrawerClose"
      :auto-focus="false"
      :mask-closable="false"
      close-on-esc
  >
    <n-drawer-content :title="drawerDetailTitle" closable>
      <n-form
          :disabled="drawerDetailTitle === ModeTypeEnum.DETAIL"
          ref="drawerDetailFormRef"
          :model="drawerDetailFormModel"
          :rules="drawerDetailFormRules"
      >
        <n-grid :cols="24" :x-gap="12">
          <n-form-item-gi v-if="drawerDetailFormModel.id" :span="24" label="主键" path="noticeTitle">
            <n-tag>{{ drawerDetailFormModel.id }}</n-tag>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="通知标题" path="noticeTitle">
            <n-input v-model:value="drawerDetailFormModel.noticeTitle" placeholder="请输入标题"/>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="通知描述" path="noticeDesc">
            <n-input v-model:value="drawerDetailFormModel.noticeDesc" placeholder="请输入描述"/>
          </n-form-item-gi>
          <n-form-item-gi :span="24" label="通知内容" path="noticeContent">
            <n-input v-model:value="drawerDetailFormModel.noticeContent" type="textarea" placeholder="请输入内容"/>
          </n-form-item-gi>
          <n-form-item-gi :span="12" label="通知类型" path="noticeType">
            <n-select
                :options="dictStore.getDictTagOptions('notice-type')"
                v-model:value="drawerDetailFormModel.noticeType"
                placeholder="请选择类型"
                clearable
            />
          </n-form-item-gi>
          <n-form-item-gi :span="12" label="自定义图标" path="noticeIcon">
            <icon-picker
                :disabled="drawerDetailFormModel.noticeType !== 'default' || drawerDetailTitle === ModeTypeEnum.DETAIL"
                v-model:value="drawerDetailFormModel.noticeIcon"
            />
          </n-form-item-gi>
          <n-form-item-gi :span="12" label="接收类型" path="noticeReceiveType">
            <n-select
                :options="dictStore.getDictTagOptions('notice-receive-type')"
                v-model:value="drawerDetailFormModel.noticeReceiveType"
                placeholder="请选择接收类型"
                clearable
            />
          </n-form-item-gi>
          <n-form-item-gi
              :span="12"
              label="指定接收用户"
              path="noticeReceiverIds"
          >
            <n-select
                :disabled="NoticeReceiveTypeEnum.USER !== drawerDetailFormModel.noticeReceiveType"
                :options="drawerNoticeReceiverSelectOption"
                v-model:value="drawerDetailFormModel.noticeReceiverIds"
                @focus="handleBlurNoticeReceiverSelect"
                :loading="drawerNoticeReceiverLoading"
                multiple
                clearable
            />
          </n-form-item-gi>
          <n-form-item-gi :span="12" label="发布时间" path="noticePublishTimeNumber">
            <n-date-picker
                v-model:value="drawerDetailFormModel.noticePublishTimeNumber"
                value-format="yyyy-MM-dd HH:mm:ss"
                default-time="00:00:00"
                type="datetime"
                placeholder="请选择发布时间"
                clearable
                w-full
                :is-date-disabled="(current:number) => current > drawerDetailFormModel.noticeExpireTimeNumber"
            />
          </n-form-item-gi>
          <n-form-item-gi :span="12" label="过期时间" path="noticeExpireTimeNumber">
            <n-date-picker
                v-model:value="drawerDetailFormModel.noticeExpireTimeNumber"
                default-time="00:00:00"
                value-format="yyyy-MM-dd HH:mm:ss"
                type="datetime"
                placeholder="请选择过期时间"
                :is-date-disabled="(current:number) => current < drawerDetailFormModel.noticePublishTimeNumber"
                clearable
                w-full
            />
          </n-form-item-gi>
        </n-grid>
      </n-form>
      <template #footer>
        <n-button secondary type="primary" @click="handleClickSubmit" :loading="drawerDetailSubmitLoading">提交
        </n-button>
      </template>
    </n-drawer-content>
  </n-drawer>
</template>
<style scoped>
</style>
